#include <linux/fs.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/device.h>


static unsigned int major;
static char drv_buf[100];
static struct class *hello_class;

static int hello_open(struct inode *inode, struct file *filp)
{
   printk("%s %s %d\n", __FILE__,__FUNCTION__, __LINE__);
   return 0;
}

static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	int ret;
	//unsigned long len = strlen(drv_buf);
	//len = len > 100 ? 100 : len;
    unsigned long len = count > 100 ? 100 : count;
	printk("%s %s %d\n", __FILE__,__FUNCTION__, __LINE__);
	ret = copy_to_user(buf, drv_buf, len);
	return len;
}

static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	int ret;
	//unsigned long len = strlen(buf);//Segmentation fault
	//len = len > 100 ? 100 : len;
	unsigned long len = count > 100 ? 100 : count;
	printk("%s %s %d\n", __FILE__,__FUNCTION__, __LINE__);
	ret = copy_from_user(drv_buf, buf, len);
	return len;
}
static int hello_release (struct inode *inode, struct file *filp)
{
	printk("%s %s %d\n", __FILE__,__FUNCTION__, __LINE__);
	return 0;
}

static const struct file_operations hello_drv = {
    .owner      = THIS_MODULE,
	.read		= hello_read,
	.write		= hello_write,
	.open		= hello_open,
	.release    = hello_release,
};

static int hello_drv_init(void)
{
   int err;
   major = register_chrdev(0, "hello_drv", &hello_drv);

   hello_class = class_create(THIS_MODULE, "hello_class");
	if (IS_ERR(hello_class)) 
	{
		err = PTR_ERR(hello_class);
		return -1;
	}
    
	device_create(hello_class, NULL, MKDEV(major, 0), NULL,"hello");  /* /dev/hello */

   return 0;
}

static void hello_drv_exit(void)
{
   device_destroy(hello_class, MKDEV(major, 0));
   class_destroy(hello_class);
   unregister_chrdev(major, "hello_drv");
}

module_init(hello_drv_init);
module_exit(hello_drv_exit);
MODULE_LICENSE("GPL");